Package org.python.pydev.ui.pythonpathconf

Source Code of org.python.pydev.ui.pythonpathconf.AbstractInterpreterEditor$CancelException

/**
* Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Eclipse Public License (EPL).
* Please see the license.txt included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
/*
* Author: atotic
* Created: Sep 8, 2003
*/
package org.python.pydev.ui.pythonpathconf;

import java.io.ByteArrayOutputStream;
import java.io.CharArrayWriter;
import java.io.File;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.zip.ZipFile;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.debug.ui.EnvironmentTab;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;
import org.python.copiedfromeclipsesrc.JDTNotAvailableException;
import org.python.copiedfromeclipsesrc.PythonListEditor;
import org.python.pydev.core.IInterpreterInfo;
import org.python.pydev.core.IInterpreterManager;
import org.python.pydev.core.PropertiesHelper;
import org.python.pydev.core.bundle.ImageCache;
import org.python.pydev.core.docutils.StringUtils;
import org.python.pydev.core.log.Log;
import org.python.pydev.core.uiutils.AsynchronousProgressMonitorDialog;
import org.python.pydev.jython.IPythonInterpreter;
import org.python.pydev.jython.JythonPlugin;
import org.python.pydev.plugin.PydevPlugin;
import org.python.pydev.runners.SimpleJythonRunner;
import org.python.pydev.ui.TabVariables;
import org.python.pydev.ui.UIConstants;
import org.python.pydev.ui.dialogs.InterpreterInputDialog;
import org.python.pydev.ui.dialogs.PyDialogHelpers;
import org.python.pydev.ui.filetypes.FileTypesPreferencesPage;

import com.aptana.shared_core.io.FileUtils;
import com.aptana.shared_core.structure.Tuple;

/**
* Field editor for a list of python interpreter with executable verifier.
*
* <p>
* heavily inspired by org.eclipse.jface.preference.PathEditor
* <p>
* Tries to run python binary to make sure it exists
*
* Subclasses must implement :<code>parseString</code>,<code>createList</code>,<code>getNewInputObject</code>
*/

public abstract class AbstractInterpreterEditor extends PythonListEditor {

    /**
     * Interpreter manager we are using (given at init)
     */
    private IInterpreterManager interpreterManager;

    /**
     * Tree to add libs.
     */
    private Tree treeWithLibs;

    /**
     * This is the control where the interpreters are shown
     */
    /*default*/Tree treeWithInterpreters;

    /**
     * Images
     */
    private Image imageSystemLibRoot;
    private Image imageSystemLib;
    private Image environmentImage;

    private Composite boxSystem;

    private Button addBtSystemFolder;

    private Button removeBtSystemFolder;

    private Button addBtSystemJar;

    private SelectionListener selectionListenerSystem;

    private Map<String, IInterpreterInfo> nameToInfo = new HashMap<String, IInterpreterInfo>();

    private Set<String> exeOrJarOfInterpretersToRestore = new HashSet<String>();
    private Set<String> exeOrJarOfInterpretersWithBuiltinsChanged = new HashSet<String>();
    private Set<String> exeOrJarOfInterpretersWithPredefinedChanged = new HashSet<String>();
    private Set<String> exeOrJarOfInterpretersWithStringSubstitutionChanged = new HashSet<String>();

    private void clearInfos() {
        nameToInfo.clear();
        exeOrJarOfInterpretersToRestore.clear();
        exeOrJarOfInterpretersWithBuiltinsChanged.clear();
        exeOrJarOfInterpretersWithPredefinedChanged.clear();
        exeOrJarOfInterpretersWithStringSubstitutionChanged.clear();
    }

    public Set<String> getInterpreterExeOrJarToRestoreAndClear() {
        HashSet<String> set = new HashSet<String>();
        set.addAll(exeOrJarOfInterpretersToRestore);
        set.addAll(exeOrJarOfInterpretersWithBuiltinsChanged);
        set.addAll(exeOrJarOfInterpretersWithPredefinedChanged);
        set.addAll(exeOrJarOfInterpretersWithStringSubstitutionChanged);

        exeOrJarOfInterpretersToRestore.clear();
        exeOrJarOfInterpretersWithBuiltinsChanged.clear();
        exeOrJarOfInterpretersWithPredefinedChanged.clear();
        exeOrJarOfInterpretersWithStringSubstitutionChanged.clear();

        return set;
    }

    public IInterpreterInfo[] getExesList() {
        TreeItem[] items = treeWithInterpreters.getItems();
        ArrayList<IInterpreterInfo> infos = new ArrayList<IInterpreterInfo>();
        for (TreeItem exe : items) {
            IInterpreterInfo info = this.nameToInfo.get(getNameFromTreeItem(exe));
            if (info == null) {
                Log.log("Didn't expect interpreter info to be null in the memory: " + exe);
            } else {
                infos.add(info);
            }
        }
        return infos.toArray(new IInterpreterInfo[infos.size()]);
    }

    protected String getNameFromTreeItem(TreeItem treeItem) {
        return treeItem.getText(0);
    }

    /*default*/InterpreterInfo getSelectedInfo() {
        if (treeWithInterpreters.getSelectionCount() == 1) {
            TreeItem[] selection = treeWithInterpreters.getSelection();
            return (InterpreterInfo) this.nameToInfo.get(getNameFromTreeItem(selection[0]));
        }
        return null;
    }

    /**
     * Creates a path field editor linked to the preference name passed
     *
     * @param labelText the label text of the field editor
     * @param parent the parent of the field editor's control
     */
    protected AbstractInterpreterEditor(String preferenceName, String labelText, Composite parent,
            IInterpreterManager interpreterManager) {
        init(preferenceName, labelText);
        this.interpreterManager = interpreterManager;

        IInterpreterInfo[] interpreters = this.interpreterManager.getInterpreterInfos();
        clearInfos();
        for (IInterpreterInfo interpreterInfo : interpreters) {
            if (interpreterInfo != null) {
                nameToInfo.put(interpreterInfo.getName(), interpreterInfo.makeCopy());
            }
        }

        if (USE_ICONS) {
            ImageCache imageCache = PydevPlugin.getImageCache();
            imageSystemLibRoot = imageCache.get(UIConstants.LIB_SYSTEM_ROOT);
            imageSystemLib = imageCache.get(UIConstants.LIB_SYSTEM);
            environmentImage = imageCache.get(UIConstants.ENVIRONMENT_ICON);
        }
        createControl(parent);
        updateTree();
    }

    /**
     * @see org.eclipse.jface.preference.FieldEditor#createControl(org.eclipse.swt.widgets.Composite)
     */
    protected void createControl(Composite parent) {
        super.createControl(parent);
        treeWithInterpreters = getListControl(parent);
        treeWithInterpreters.addSelectionListener(new SelectionListener() {

            public void widgetSelected(SelectionEvent e) {
                updateTree();
            }

            public void widgetDefaultSelected(SelectionEvent e) {
                updateTree();
            }

        });

        treeWithInterpreters.addKeyListener(new KeyListener() {

            public void keyReleased(KeyEvent e) {
            }

            public void keyPressed(KeyEvent e) {
                if (e.keyCode == SWT.F2) {
                    renameSelection();
                }
            }
        });

        treeWithInterpreters.addMouseListener(new MouseListener() {

            public void mouseUp(MouseEvent e) {
            }

            public void mouseDown(MouseEvent e) {
            }

            public void mouseDoubleClick(MouseEvent e) {
                renameSelection();
            }
        });
    }

    private void renameSelection() {
        int index = getSelectionIndex();
        if (index >= 0) {
            TreeItem curr = treeWithInterpreters.getItem(index);

            final String initialName = getNameFromTreeItem(curr);
            InputDialog d = new InputDialog(this.getShell(), "New name",
                    "Please specify the new name of the interpreter.", initialName, new IInputValidator() {
                        public String isValid(String newText) {
                            if (newText == null || newText.trim().equals("")) {
                                return "Please specify a non-empty name.";
                            }
                            newText = newText.trim();
                            if (newText.equals(initialName)) {
                                return null;
                            }
                            return getDuplicatedMessageError(newText, null);
                        }
                    });

            int retCode = d.open();
            if (retCode == InputDialog.OK) {
                String newName = d.getValue().trim();
                if (!newName.equals(initialName)) {
                    IInterpreterInfo info = this.nameToInfo.get(initialName);
                    info.setName(newName);
                    curr.setText(0, newName);
                    this.nameToInfo.remove(initialName);
                    this.nameToInfo.put(newName, info);
                    this.exeOrJarOfInterpretersToRestore.add(info.getExecutableOrJar());
                }
            }
        }
    }

    /**
     * @param parent
     * @return
     */
    private Tree getTreeLibsControl(Composite parent) {
        if (treeWithLibs == null) {
            treeWithLibs = new Tree(parent, SWT.BORDER | SWT.MULTI);
            treeWithLibs.setFont(parent.getFont());
            treeWithLibs.addDisposeListener(new DisposeListener() {
                public void widgetDisposed(DisposeEvent event) {
                    treeWithLibs = null;
                }
            });
        }
        return treeWithLibs;
    }

    @Override
    protected void disposeOfTreeItem(TreeItem t) {
        String nameFromTreeItem = this.getNameFromTreeItem(t);
        this.nameToInfo.remove(nameFromTreeItem);
        super.disposeOfTreeItem(t);
    }

    protected void adjustForNumColumns(int numColumns) {
        super.adjustForNumColumns(numColumns);
        ((GridData) tabFolder.getLayoutData()).horizontalSpan = numColumns;
    }

    protected TabFolder tabFolder;

    private EnvironmentTab environmentTab;

    private MyEnvWorkingCopy workingCopy = new MyEnvWorkingCopy();

    private TabVariables tabVariables;

    private AbstractListWithNewRemoveControl forcedBuiltins;

    private AbstractListWithNewRemoveControl predefinedCompletions;

    /**
     * @see org.eclipse.jface.preference.ListEditor#doFillIntoGrid(org.eclipse.swt.widgets.Composite, int)
     */
    protected void doFillIntoGrid(Composite parent, int numColumns) {
        super.doFillIntoGrid(parent, numColumns);
        GridData gd = new GridData();

        tabFolder = new TabFolder(parent, SWT.None);
        gd = new GridData();
        gd.horizontalAlignment = SWT.FILL;
        gd.verticalAlignment = SWT.FILL;
        gd.grabExcessVerticalSpace = true;
        gd.horizontalSpan = numColumns;
        tabFolder.setLayoutData(gd);

        createTreeLibsControlTab();

        //----------------------- FORCED BUILTINS
        forcedBuiltins = new AbstractListWithNewRemoveControl(this) {

            protected List<String> getStringsFromInfo(InterpreterInfo info) {
                ArrayList<String> ret = new ArrayList<String>();
                for (Iterator<String> iter = info.forcedLibsIterator(); iter.hasNext();) {
                    ret.add(iter.next());
                }
                return ret;
            }

            protected void removeSelectedFrominfo(InterpreterInfo info, String[] builtins) {
                for (String builtin : builtins) {
                    info.removeForcedLib(builtin);
                }
                exeOrJarOfInterpretersWithBuiltinsChanged.add(info.getExecutableOrJar());
            }

            protected String getInput() {
                IInputValidator validator = new IInputValidator() {

                    public String isValid(String newText) {
                        for (char c : newText.toCharArray()) {
                            if (!Character.isJavaIdentifierPart(c) && c != ' ' && c != ',' && c != '.') {
                                return "Can only accept valid python module names (char: '" + c + "' not accepted)";
                            }
                        }
                        return null;
                    }
                };
                InputDialog d = new InputDialog(getShell(), "Builtin to add", "Builtin to add (comma separated)", "",
                        validator);

                int retCode = d.open();
                String builtins = null;
                if (retCode == InputDialog.OK) {
                    builtins = d.getValue();
                }
                return builtins;
            }

            protected void addInputToInfo(InterpreterInfo info, String builtins) {
                java.util.List<String> split = StringUtils.splitAndRemoveEmptyTrimmed(builtins, ',');
                for (String string : split) {
                    String trimmed = string.trim();
                    if (trimmed.length() > 0) {
                        info.addForcedLib(trimmed);
                    }
                }
                exeOrJarOfInterpretersWithBuiltinsChanged.add(info.getExecutableOrJar());
            }

        };
        forcedBuiltins.createTab("Forced Builtins", "Forced Builtins (check <a>Manual</a> for more info).");

        //----------------------- PREDEFINED COMPLETIONS
        predefinedCompletions = new AbstractListWithNewRemoveControl(this) {

            private Button addAPIBt;

            protected List<String> getStringsFromInfo(InterpreterInfo info) {
                return info.getPredefinedCompletionsPath();
            }

            protected void removeSelectedFrominfo(InterpreterInfo info, String[] items) {
                for (String item : items) {
                    info.removePredefinedCompletionPath(item);
                }
                exeOrJarOfInterpretersWithPredefinedChanged.add(info.getExecutableOrJar());
            }

            protected String getInput() {
                DirectoryDialog dialog = new DirectoryDialog(getShell());
                dialog.setFilterPath(lastDirectoryDialogPath);
                String filePath = dialog.open();
                if (filePath != null) {
                    lastDirectoryDialogPath = filePath;
                }
                return filePath;
            }

            protected void addInputToInfo(InterpreterInfo info, String item) {
                info.addPredefinedCompletionsPath(item);
                exeOrJarOfInterpretersWithPredefinedChanged.add(info.getExecutableOrJar());
            }

            protected void createButtons(AbstractInterpreterEditor interpreterEditor) {
                super.createButtons(interpreterEditor);
                addAPIBt = interpreterEditor.createBt(box, "Add from QScintilla api file", this);//$NON-NLS-1$
            }

            public void widgetDisposed(DisposeEvent event) {
                super.widgetDisposed(event);
                if (addAPIBt != null) {
                    addAPIBt.dispose();
                    addAPIBt = null;
                }
            }

            public void widgetSelected(SelectionEvent event) {
                super.widgetSelected(event);
                Widget widget = event.widget;
                if (widget == addAPIBt) {
                    addAPIBt();
                }
            }

            private void addAPIBt() {
                final AbstractInterpreterEditor interpreterEditor = this.container.get();
                Assert.isNotNull(interpreterEditor);

                final InterpreterInfo info = interpreterEditor.getSelectedInfo();
                if (info != null) {
                    FileDialog dialog = new FileDialog(getShell(), SWT.PRIMARY_MODAL | SWT.MULTI);

                    dialog.setFilterExtensions(new String[] { "*.api" });
                    dialog.setText("Select .api file to be converted to .pypredef.");

                    dialog.setFilterPath(lastFileDialogPath);
                    final String filePath = dialog.open();
                    if (filePath != null) {
                        lastFileDialogPath = filePath;
                        File filePath1 = new File(filePath);
                        final String dir = filePath1.getParent();

                        IInputValidator validator = new IInputValidator() {

                            public String isValid(String newText) {
                                if (newText.length() == 0) {
                                    return "Number not provided.";
                                }
                                try {
                                    Integer.parseInt(newText);
                                } catch (NumberFormatException e) {
                                    return "The string: " + newText + " is not a valid integer.";
                                }
                                return null;
                            }
                        };
                        final InputDialog d = new InputDialog(
                                getShell(),
                                "Number of tokens to consider module",
                                "Please specify the number of tokens to consider a module from the .api file\n\n"
                                        + "i.e.: if there's a PyQt4.QtCore.QObject and PyQt4.QtCore is a module and QtObject "
                                        + "is the first class, the number of tokens to consider a module would be 2 (one for "
                                        + "PyQt4 and another for QtCore).", "", validator);

                        int retCode = d.open();
                        final ByteArrayOutputStream output = new ByteArrayOutputStream();
                        if (retCode == InputDialog.OK) {

                            ProgressMonitorDialog monitorDialog = new AsynchronousProgressMonitorDialog(getShell());
                            monitorDialog.setBlockOnOpen(false);
                            final Exception[] exception = new Exception[1];
                            try {
                                IRunnableWithProgress operation = new IRunnableWithProgress() {

                                    public void run(final IProgressMonitor monitor) throws InvocationTargetException,
                                            InterruptedException {
                                        monitor.beginTask("Restoring PYTHONPATH", IProgressMonitor.UNKNOWN);

                                        IPythonInterpreter interpreter = JythonPlugin
                                                .newPythonInterpreter(false, false);
                                        interpreter.setErr(output);
                                        interpreter.setOut(output);
                                        HashMap<String, Object> locals = new HashMap<String, Object>();
                                        locals.put("api_file", filePath);
                                        locals.put("parts_for_module", d.getValue());
                                        locals.put("cancel_monitor", monitor);
                                        try {
                                            JythonPlugin.exec(locals, "convert_api_to_pypredef.py", interpreter);
                                        } catch (Exception e) {
                                            Log.log(e + "\n\n" + output.toString());
                                            exception[0] = e;
                                        }

                                        monitor.done();
                                    }
                                };

                                monitorDialog.run(true, true, operation);

                            } catch (Exception e) {
                                Log.log(e);
                            }

                            Exception e = exception[0];
                            String contents = output.toString();
                            if (e == null && contents.indexOf("SUCCESS") != -1) {
                                addInputToInfo(info, dir);
                                interpreterEditor.updateTree();
                            } else {
                                if (e != null) {
                                    MessageDialog.openError(getShell(), "Error creating .pypredef files",
                                            e.getMessage() + "\n\n" + contents);
                                } else {
                                    MessageDialog.openError(getShell(), "Error creating .pypredef files", contents);
                                }
                            }
                        }
                    }
                }
            }

        };
        predefinedCompletions.createTab("Predefined", "Predefined completions (check <a>Manual</a> for more info).");
        createEnvironmentVariablesTab();
        createStringSubstitutionTab();

    }

    /**
     * Creates tab to show the string substitution variables.
     */
    private void createStringSubstitutionTab() {
        Map<String, String> initialVariables = new HashMap<String, String>();
        tabVariables = new TabVariables(tabFolder, initialVariables);
    }

    /**
     * Creates tab to show the environment variables.
     */
    private void createEnvironmentVariablesTab() {
        Composite parent;
        TabItem tabItem = new TabItem(tabFolder, SWT.None);
        tabItem.setText("Environment");
        tabItem.setImage(environmentImage);

        Composite composite = new Composite(tabFolder, SWT.None);
        parent = composite;
        composite.setLayout(new GridLayout(1, false));

        environmentTab = new EnvironmentTab() {
            protected void createAppendReplace(Composite parent) {
                super.createAppendReplace(parent);
                appendEnvironment.setVisible(false);
                replaceEnvironment.setVisible(false);
            }
        };
        environmentTab.createControl(parent);

        GridData gd = new GridData();
        gd.horizontalAlignment = SWT.FILL;
        gd.verticalAlignment = SWT.FILL;
        gd.grabExcessHorizontalSpace = true;
        gd.grabExcessVerticalSpace = true;
        environmentTab.getControl().setLayoutData(gd);

        tabItem.setControl(composite);
    }

    /**
     * Creates tab to show the pythonpath (libraries)
     */
    private void createTreeLibsControlTab() {
        Composite parent;
        GridData gd;
        TabItem tabItem = new TabItem(tabFolder, SWT.None);
        tabItem.setText("Libraries");
        tabItem.setImage(imageSystemLibRoot);

        Composite composite = new Composite(tabFolder, SWT.None);
        parent = composite;
        composite.setLayout(new GridLayout(2, false));

        Label l1 = new Label(parent, SWT.None);
        l1.setText("System PYTHONPATH");
        gd = new GridData();
        gd.horizontalSpan = 2;
        l1.setLayoutData(gd);

        //the tree
        treeWithLibs = getTreeLibsControl(parent);
        gd = new GridData();
        gd.horizontalAlignment = SWT.FILL;
        gd.verticalAlignment = SWT.FILL;
        gd.grabExcessHorizontalSpace = true;
        gd.grabExcessVerticalSpace = true;
        gd.heightHint = 200;
        treeWithLibs.setLayoutData(gd);

        //buttons at the side of the tree
        Composite control = getButtonBoxControlSystem(parent);
        gd = new GridData();
        gd.verticalAlignment = GridData.BEGINNING;
        control.setLayoutData(gd);

        tabItem.setControl(composite);
    }

    /**
     * Returns this field editor's button box containing the Add Source Folder, Add Jar and Remove
     *
     * @param parent the parent control
     * @return the button box
     */
    public Composite getButtonBoxControlSystem(Composite parent) {
        if (boxSystem == null) {
            boxSystem = new Composite(parent, SWT.NULL);
            GridLayout layout = new GridLayout();
            layout.marginWidth = 0;
            boxSystem.setLayout(layout);
            addBtSystemFolder = createBt(boxSystem, "New Folder", getSelectionListenerSystem());//$NON-NLS-1$
            switch (this.interpreterManager.getInterpreterType()) {

                case IInterpreterManager.INTERPRETER_TYPE_JYTHON:
                    addBtSystemJar = createBt(boxSystem, "New Jar/Zip(s)", getSelectionListenerSystem());//$NON-NLS-1$
                    break;

                default:
                    addBtSystemJar = createBt(boxSystem, "New Egg/Zip(s)", getSelectionListenerSystem());//$NON-NLS-1$

            }
            removeBtSystemFolder = createBt(boxSystem, "ListEditor.remove", getSelectionListenerSystem());//$NON-NLS-1$
            boxSystem.addDisposeListener(new DisposeListener() {
                public void widgetDisposed(DisposeEvent event) {
                    addBtSystemJar = null;
                    addBtSystemFolder = null;
                    removeBtSystemFolder = null;
                    boxSystem = null;
                }
            });

        } else {
            checkParent(boxSystem, parent);
        }

        return boxSystem;
    }

    private static String lastDirectoryDialogPath = null;
    private static String lastFileDialogPath = null;

    /**
     * Returns this field editor's selection listener. The listener is created if necessary.
     *
     * @return the selection listener
     */
    private SelectionListener getSelectionListenerSystem() {
        if (selectionListenerSystem == null) {
            selectionListenerSystem = new SelectionAdapter() {
                public void widgetSelected(SelectionEvent event) {
                    if (treeWithInterpreters.getSelectionCount() == 1) {
                        TreeItem[] selection = treeWithInterpreters.getSelection();
                        String nameFromTreeItem = getNameFromTreeItem(selection[0]);
                        InterpreterInfo info = (InterpreterInfo) nameToInfo.get(nameFromTreeItem);
                        exeOrJarOfInterpretersToRestore.add(info.getExecutableOrJar());

                        Widget widget = event.widget;
                        if (widget == addBtSystemFolder) {
                            DirectoryDialog dialog = new DirectoryDialog(getShell());
                            dialog.setFilterPath(lastDirectoryDialogPath);
                            String filePath = dialog.open();
                            if (filePath != null) {
                                lastDirectoryDialogPath = filePath;
                                info.libs.add(filePath);
                            }

                        } else if (widget == addBtSystemJar) {
                            FileDialog dialog = new FileDialog(getShell(), SWT.PRIMARY_MODAL | SWT.MULTI);

                            switch (AbstractInterpreterEditor.this.interpreterManager.getInterpreterType()) {

                                case IInterpreterManager.INTERPRETER_TYPE_JYTHON:
                                    dialog.setFilterExtensions(FileTypesPreferencesPage
                                            .getWildcardJythonValidZipFiles());
                                    break;

                                default:
                                    dialog.setFilterExtensions(FileTypesPreferencesPage
                                            .getWildcardPythonValidZipFiles());
                            }

                            dialog.setFilterPath(lastFileDialogPath);
                            String filePath = dialog.open();
                            if (filePath != null) {
                                lastFileDialogPath = filePath;
                                File filePath1 = new File(filePath);
                                String dir = filePath1.getParent();

                                String[] fileNames = dialog.getFileNames();
                                for (String f : fileNames) {
                                    f = dir + File.separatorChar + f;
                                    if (!info.libs.contains(f)) {
                                        info.libs.add(f);
                                    }
                                }
                            }

                        } else if (widget == removeBtSystemFolder) {
                            TreeItem[] libSelection = treeWithLibs.getSelection();
                            for (int i = 0; i < libSelection.length; i++) {
                                TreeItem s = libSelection[i];
                                String text = s.getText();
                                info.libs.remove(text);
                                //                                changed = true;
                            }
                        }
                        updateTree();
                    }
                }
            };
        }
        return selectionListenerSystem;
    }

    /**
     * Helper method to create a push button.
     *
     * @param parent the parent control
     * @param key the resource name used to supply the button's label text
     * @param listenerToAdd
     * @return Button
     */
    /*default*/Button createBt(Composite parent, String key, SelectionListener listenerToAdd) {
        Button button = new Button(parent, SWT.PUSH);
        button.setText(JFaceResources.getString(key));
        button.setFont(parent.getFont());
        GridData data = new GridData(GridData.FILL_HORIZONTAL);
        //        data.heightHint = convertVerticalDLUsToPixels(button, IDialogConstants.BUTTON_HEIGHT);
        int widthHint = convertHorizontalDLUsToPixels(button, IDialogConstants.BUTTON_WIDTH);
        data.widthHint = Math.max(widthHint, button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x);
        button.setLayoutData(data);
        button.addSelectionListener(listenerToAdd);
        return button;
    }

    /**
     * @param listControl
     */
    public void updateTree() {
        int index = this.getSelectionIndex();
        if (index >= 0) {
            TreeItem item = treeWithInterpreters.getItem(index);
            fillPathItemsFromName(getNameFromTreeItem(item));
        } else {
            fillPathItemsFromName(null);
            if (treeWithInterpreters.getItemCount() > 0) {
                treeWithInterpreters.setSelection(treeWithInterpreters.getItem(0));
                selectionChanged();
                fillPathItemsFromName(getNameFromTreeItem(treeWithInterpreters.getItem(0)));
            }
        }
    }

    public Shell getShell() {
        return super.getShell();
    }

    /**
     * @param s
     *
     */
    private void fillPathItemsFromName(String name) {
        treeWithLibs.removeAll();
        this.forcedBuiltins.removeAllFromList();
        this.predefinedCompletions.removeAllFromList();

        //before any change, apply the changes in the previous info (if not set, that's ok)
        InterpreterInfo workingCopyInfo = workingCopy.getInfo();
        if (workingCopyInfo != null) {
            environmentTab.performApply(workingCopy);
            Properties propertiesFromMap = PropertiesHelper.createPropertiesFromMap(this.tabVariables
                    .getTreeItemsAsMap());
            Properties stringSubstitutionVariables = workingCopyInfo.getStringSubstitutionVariables();
            boolean equals = false;
            if (stringSubstitutionVariables == null) {
                if (propertiesFromMap == null || propertiesFromMap.size() == 0) {
                    equals = true;
                }
            } else {
                equals = stringSubstitutionVariables.equals(propertiesFromMap);
            }
            if (!equals) {
                exeOrJarOfInterpretersWithStringSubstitutionChanged.add(workingCopyInfo.getExecutableOrJar());
                workingCopyInfo.setStringSubstitutionVariables(propertiesFromMap);
            }
        }

        if (name != null) {
            TreeItem item = new TreeItem(treeWithLibs, SWT.NONE);
            item.setText("System libs");
            item.setImage(imageSystemLibRoot);

            InterpreterInfo info = (InterpreterInfo) this.nameToInfo.get(name);
            if (info == null) {
                Log.log("Didn't expect interpreter info to be null in the memory: " + name);
            } else {
                for (Iterator<String> iter = info.libs.iterator(); iter.hasNext();) {
                    TreeItem subItem = new TreeItem(item, SWT.NONE);
                    subItem.setText(iter.next());
                    subItem.setImage(imageSystemLib);
                }
                item.setExpanded(true);

                this.forcedBuiltins.update(info);
                this.predefinedCompletions.update(info);
                workingCopy.setInfo(info);
            }

            environmentTab.initializeFrom(workingCopy);
            Properties stringSubstitutionVariables = info.getStringSubstitutionVariables();
            if (stringSubstitutionVariables != null) {
                this.tabVariables.setTreeItemsFromMap(PropertiesHelper
                        .createMapFromProperties(stringSubstitutionVariables));
            } else {
                this.tabVariables.setTreeItemsFromMap(new HashMap<String, String>());
            }
        }

    }

    /**
     * @return a string with the extensions that are accepted for the interpreter
     */
    public abstract String[] getInterpreterFilterExtensions();

    @Override
    protected Tuple<String, String> getNewInputObject(boolean autoConfig) {
        CharArrayWriter charWriter = new CharArrayWriter();
        PrintWriter logger = new PrintWriter(charWriter);
        logger.println("Information about process of adding new interpreter:");
        try {
            Tuple<String, String> interpreterNameAndExecutable = null;
            if (autoConfig) {
                try {
                    interpreterNameAndExecutable = getAutoNewInput();
                } catch (CancelException e) {
                    //user canceled.
                    return null;
                }
                if (interpreterNameAndExecutable == null) {
                    reportAutoConfigProblem(null);
                    return null;
                }
            } else {

                InterpreterInputDialog dialog = new InterpreterInputDialog(getShell(), "Select interpreter",
                        "Enter the name and executable of your interpreter", this);

                logger.println("- Opening dialog to request executable (or jar).");
                int result = dialog.open();

                if (result == Window.OK) {
                    interpreterNameAndExecutable = dialog.getKeyAndValueEntered();
                } else {
                    return null;
                }
            }

            boolean foundError = checkInterpreterNameAndExecutable(interpreterNameAndExecutable, logger,
                    "Error getting info on interpreter");

            if (foundError) {
                return null;
            }

            logger.println("- Chosen interpreter (name and file):'" + interpreterNameAndExecutable);

            if (interpreterNameAndExecutable != null && interpreterNameAndExecutable.o2 != null) {
                //ok, now that we got the file, let's see if it is valid and get the library info.
                logger.println("- Ok, file is non-null. Getting info on:" + interpreterNameAndExecutable.o2);
                ProgressMonitorDialog monitorDialog = new AsynchronousProgressMonitorDialog(this.getShell());
                monitorDialog.setBlockOnOpen(false);
                ObtainInterpreterInfoOperation operation;
                while (true) {
                    operation = new ObtainInterpreterInfoOperation(interpreterNameAndExecutable.o2, logger,
                            interpreterManager);
                    monitorDialog.run(true, false, operation);
                    if (operation.e != null) {
                        logger.println("- Some error happened while getting info on the interpreter:");
                        operation.e.printStackTrace(logger);

                        if (operation.e instanceof SimpleJythonRunner.JavaNotConfiguredException) {
                            SimpleJythonRunner.JavaNotConfiguredException javaNotConfiguredException = (SimpleJythonRunner.JavaNotConfiguredException) operation.e;

                            ErrorDialog.openError(this.getShell(), "Error getting info on interpreter",
                                    javaNotConfiguredException.getMessage(), PydevPlugin.makeStatus(IStatus.ERROR,
                                            "Java vm not configured.\n", javaNotConfiguredException));

                        } else if (operation.e instanceof JDTNotAvailableException) {
                            JDTNotAvailableException noJdtException = (JDTNotAvailableException) operation.e;
                            ErrorDialog.openError(this.getShell(), "Error getting info on interpreter",
                                    noJdtException.getMessage(),
                                    PydevPlugin.makeStatus(IStatus.ERROR, "JDT not available.\n", noJdtException));

                        } else {
                            if (autoConfig) {
                                reportAutoConfigProblem(operation.e);

                            } else {
                                String errorMsg = "Error getting info on interpreter.\n\n"
                                        + "Common reasons include:\n\n" + "- Using an unsupported version\n"
                                        + "  (Python and Jython require at least version 2.1 and Iron Python 2.6).\n"
                                        + "\n" + "- Specifying an invalid interpreter\n"
                                        + "  (usually a link to the actual interpreter on Mac or Linux)" + "";
                                //show the user a message (so that it does not fail silently)...
                                ErrorDialog.openError(this.getShell(), "Unable to get info on the interpreter.",
                                        errorMsg, PydevPlugin.makeStatus(IStatus.ERROR, "See error log for details.",
                                                operation.e));
                            }
                        }

                        throw operation.e;

                    } else {
                        if (operation.result != null) {
                            foundError = checkInterpreterNameAndExecutable(new Tuple<String, String>(
                                    interpreterNameAndExecutable.o1, operation.result.executableOrJar), logger,
                                    "Error adding interpreter");

                            if (foundError) {
                                return null;
                            }

                            try {
                                //Ok, we got the result, so, let's check if things are correct (i.e.: do we have threading.py, traceback.py?)
                                HashSet<String> hashSet = new HashSet<String>();
                                hashSet.add("threading");
                                hashSet.add("traceback");

                                String[] validSourceFiles = FileTypesPreferencesPage.getValidSourceFiles();
                                Set<String> extensions = new HashSet<String>(Arrays.asList(validSourceFiles));
                                for (String s : operation.result.libs) {
                                    File file = new File(s);
                                    if (file.isDirectory()) {
                                        String[] directoryFiles = file.list();
                                        if (directoryFiles != null) {
                                            for (String found : directoryFiles) {
                                                List<String> split = StringUtils.split(found, '.');
                                                if (split.size() == 2) {
                                                    if (extensions.contains(split.get(1))) {
                                                        hashSet.remove(split.get(0));
                                                    }
                                                }
                                            }
                                        } else {
                                            logger.append("Warning: unable to get contents of directory: "
                                                    + file
                                                    + " (permission not available, it's not a dir or dir does not exist).");
                                        }
                                    } else if (file.isFile()) {
                                        //Zip file?
                                        try {
                                            ZipFile zipFile = new ZipFile(file);
                                            for (String extension : validSourceFiles) {
                                                if (zipFile.getEntry("threading." + extension) != null) {
                                                    hashSet.remove("threading");
                                                }
                                                if (zipFile.getEntry("traceback." + extension) != null) {
                                                    hashSet.remove("traceback");
                                                }
                                            }
                                        } catch (Exception e) {
                                            //ignore (not zip file)
                                        }
                                    }
                                }

                                if (hashSet.size() > 0) {
                                    //The /Lib folder wasn't there (or at least threading.py and traceback.py weren't found)
                                    int choice = PyDialogHelpers
                                            .openCriticalWithChoices(
                                                    "Error: Python stdlib source files not found.",

                                                    "Error: Python stdlib not found or stdlib found without .py files.\n"
                                                            + "\n"
                                                            + "It seems that the Python /Lib folder (which contains the standard library) "
                                                            + "was not found/selected during the install process or the stdlib does not contain "
                                                            + "the required .py files (i.e.: only has .pyc files).\n"
                                                            + "\n"
                                                            + "This folder (which contains files such as threading.py and traceback.py) is "
                                                            + "required for PyDev to function properly, and it must contain the actual source files, not "
                                                            + "only .pyc files. if you don't have the .py files in your install, please use an install from "
                                                            + "python.org or grab the standard library for your install from there.\n"
                                                            + "\n"
                                                            + "If this is a virtualenv install, the /Lib folder from the base install needs to be selected "
                                                            + "(unlike the site-packages which is optional).\n"
                                                            + "\n"
                                                            + "What do you want to do?\n\n"
                                                            + "Note: if you choose to proceed, the /Lib with the standard library .py source files must "
                                                            + "be added later on, otherwise PyDev may not function properly.",
                                                    new String[] { "Re-select folders", "Cancel", "Proceed anyways" });
                                    if (choice == 0) {
                                        //Keep on with outer while(true)
                                        continue;
                                    }
                                    if (choice != 2) {
                                        return null;
                                    }
                                }
                            } catch (Exception e) {
                                ErrorDialog.openError(this.getShell(),
                                        "Problem checking if the interpreter paths are correct.", e.getMessage(),
                                        PydevPlugin.makeStatus(IStatus.ERROR, "See error log for details.", e));

                                throw e;
                            }

                            operation.result.setName(interpreterNameAndExecutable.o1);
                            logger.println("- Success getting the info. Result:" + operation.result);

                            String newName = operation.result.getName();
                            this.nameToInfo.put(newName, operation.result.makeCopy());
                            exeOrJarOfInterpretersToRestore.add(operation.result.executableOrJar);

                            return new Tuple<String, String>(operation.result.getName(),
                                    operation.result.executableOrJar);
                        } else {
                            return null;
                        }
                    }
                }
            }

        } catch (Exception e) {
            Log.log(e);
            return null;
        } finally {
            Log.logInfo(charWriter.toString());
        }

        return null;
    }

    private boolean checkInterpreterNameAndExecutable(Tuple<String, String> interpreterNameAndExecutable,
            PrintWriter logger, String errorMsg) {
        boolean foundError = false;
        //Check auto config or dialog return.
        if (interpreterNameAndExecutable == null) {
            logger.println("- When trimmed, the chosen file was null (returning null).");

            ErrorDialog.openError(this.getShell(), errorMsg, "interpreterNameAndExecutable == null", PydevPlugin
                    .makeStatus(IStatus.ERROR, "interpreterNameAndExecutable == null", new RuntimeException()));
            foundError = true;
        }
        if (!foundError) {
            if (interpreterNameAndExecutable.o2.trim().length() == 0) {
                logger.println("- When trimmed, the chosen file was empty (returning null).");

                ErrorDialog.openError(this.getShell(), errorMsg, "interpreterNameAndExecutable size == empty",
                        PydevPlugin.makeStatus(IStatus.ERROR, "interpreterNameAndExecutable size == empty",
                                new RuntimeException()));
                foundError = true;
            }
        }
        if (!foundError) {
            String error = getDuplicatedMessageError(interpreterNameAndExecutable.o1, interpreterNameAndExecutable.o2);
            if (error != null) {
                logger.println("- Duplicated interpreter found.");
                ErrorDialog.openError(this.getShell(), errorMsg, error, PydevPlugin.makeStatus(IStatus.ERROR,
                        "Duplicated interpreter information", new RuntimeException()));
                foundError = true;
            }
        }
        return foundError;
    }

    /**
     * Gets a unique name for the interpreter based on an initial expected name.
     */
    public String getUniqueInterpreterName(final String expectedName) {
        String additional = "";
        int i = 0;
        while (getDuplicatedMessageError(expectedName + additional, null) != null) {
            i++;
            additional = String.valueOf(i);
        }
        return expectedName + additional;
    }

    /**
     * Uses the passed name and executable to see if it'll match against one of the existing
     *
     * The null parameters are ignored.
     */
    public String getDuplicatedMessageError(String interpreterName, String executableOrJar) {
        String error = null;
        if (interpreterName != null) {
            interpreterName = interpreterName.trim();
            if (this.nameToInfo.containsKey(interpreterName)) {
                error = "An interpreter is already configured with the name: " + interpreterName;
            }
        }
        if (executableOrJar != null) {
            executableOrJar = executableOrJar.trim();
            for (IInterpreterInfo info : this.nameToInfo.values()) {
                if (info.getExecutableOrJar().trim().equals(executableOrJar)) {
                    error = "An interpreter is already configured with the path: " + executableOrJar;
                }
            }
        }
        return error;
    }

    private void reportAutoConfigProblem(Exception e) {
        String errorMsg = "Unable to auto-configure the interpreter.\n"
                + "Please create a new interpreter using the 'New' button.";
        ErrorDialog.openError(this.getShell(), "Unable to auto-configure.", errorMsg,
                PydevPlugin.makeStatus(IStatus.ERROR, "Unable to gather the needed info from the system.\n" + "\n"
                        + "This usually means that your interpreter is not in\n" + "the system PATH.", e));
    }

    public static final class CancelException extends Exception {

        private static final long serialVersionUID = 1L;

    }

    public final CancelException cancelException = new CancelException();

    /**
     * @return a tuple with the name of the interpreter and the string with the file to be executed
     * (for python could be just python.exe) and for jython the jython.jar location.
     *
     * This is also be platform-dependent (so, it could be python.exe or just python)
     *
     * If it cannot be determined, the return should be null (and not a tuple with empty values)
     */
    protected abstract Tuple<String, String> getAutoNewInput() throws CancelException;

    @Override
    protected void doStore() {
        //Do nothing (all handled in the preferences page regarding the store (no longer in this editor)
    }

    @Override
    protected void doLoad() {
        if (treeWithInterpreters != null) {
            //Work with a copy of the interpreters actually configured.
            String s = interpreterManager.getPersistedString();
            IInterpreterInfo[] array = interpreterManager.getInterpretersFromPersistedString(s);
            clearInfos();
            for (int i = 0; i < array.length; i++) {
                IInterpreterInfo interpreterInfo = array[i];
                createInterpreterItem(interpreterInfo.getName(), interpreterInfo.getExecutableOrJar());
                this.nameToInfo.put(interpreterInfo.getName(), interpreterInfo.makeCopy());
            }
        }
        updateTree();
    }

    public String getPreferenceName() {
        throw new RuntimeException(
                "The preferences should be stored/gotten from the IInterpreterManager, and not directly.");
    }

    /**
     * @see org.python.copiedfromeclipsesrc.PythonListEditor#doLoadDefault()
     */
    protected void doLoadDefault() {
        //do nothing
    }

    public Tuple<String, String> getAutoNewInputFromPaths(java.util.List<String> pathsToSearch,
            String expectedFilename, String nameForUser) {
        for (String s : pathsToSearch) {
            if (s.trim().length() > 0) {
                File file = new File(s.trim());
                if (file.isDirectory()) {
                    String[] available = file.list();
                    if (available != null) {
                        for (String jar : available) {
                            if (jar.toLowerCase().equals(expectedFilename)) {
                                return new Tuple<String, String>(getUniqueInterpreterName(nameForUser),
                                        FileUtils.getFileAbsolutePath(new File(file, jar)));
                            }
                        }
                    }
                }
            }
        }
        return null;
    }

}
TOP

Related Classes of org.python.pydev.ui.pythonpathconf.AbstractInterpreterEditor$CancelException

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.